<script setup>
import * as echarts from 'echarts';
import 'echarts-gl';
import { onMounted, reactive, ref } from 'vue';
import { nextTick } from 'vue'
// 接收数据
const props = defineProps({
   data: {
    type: Array,
    default:  () => []
   }
})
let optionData = [
    {
        name: '针孔',//名称
        value: 28,//值
        height:60,
        itemStyle: {//颜色 紫色 
            color: 'rgba(37, 152, 159,1)'
        }
    }, {
        name: '油污',//蓝色
        value: 20,
        itemStyle: {
            color: 'rgba(242, 133, 58,1)',
        }
    }, {
        name: '线头',//绿色
        value: 10,
        itemStyle: {
            color: 'rgba(244, 170, 60,0.6)'
        }
    },
    {
        name: '尺寸',//橙色
        value: 16,
        itemStyle: {
            color: 'rgba(129, 200, 237,1)'
        }
    }
];

const cityGreenLand = ref(null);
const badProduct = ref(null);

const chart = ref(null);  // 获取图表实例的 ref
const seriesRef = ref([]);  // 保存 options 中 series 的引用
let option = null
const init = () => {
    //构建3d饼状图
    let myChart = echarts.init(document.getElementById('charts'));
    // 传入数据生成 option ; getPie3D(数据，透明的空心占比（调节中间空心范围的0就是普通饼1就很镂空）)
    option = getPie3D(optionData, 0.85);
    //将配置项设置进去
    myChart.setOption(option);
    //鼠标移动上去特效效果
    bindListen(myChart);
}
const getPie3D = (pieData, internalDiameterRatio) => {
    let series = [];
    let sumValue = 0;
    let startValue = 0;
    let endValue = 0;
    let legendData = [];
    let legendBfb = [];
    let k = 1 - internalDiameterRatio;
    pieData.sort((a, b) => {
        return (b.value - a.value);
    });
    // 为每一个饼图数据，生成一个 series-surface(参数曲面) 配置
    for (let i = 0; i < pieData.length; i++) {
        sumValue += pieData[i].value;
        let seriesItem = {
            //系统名称
            name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
            type: 'surface',
            //是否为参数曲面（是）
            parametric: true,
            //曲面图网格线（否）上面一根一根的
            wireframe: {
                show: false
            },
            pieData: pieData[i],
            pieStatus: {
                selected: false,
                hovered: false,
                k: k
            },
            //设置饼图在容器中的位置(目前没发现啥用)
            //   center: ['50%', '100%']
        };

        //曲面的颜色、不透明度等样式。
        if (typeof pieData[i].itemStyle != 'undefined') {
            let itemStyle = {};
            typeof pieData[i].itemStyle.color != 'undefined' ? itemStyle.color = pieData[i].itemStyle.color : null;
            typeof pieData[i].itemStyle.opacity != 'undefined' ? itemStyle.opacity = pieData[i].itemStyle.opacity : null;
            seriesItem.itemStyle = itemStyle;
        }
        series.push(seriesItem);
    }

    // 使用上一次遍历时，计算出的数据和 sumValue，调用 getParametricEquation 函数，
    // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation，也就是实现每一个扇形。
    legendData = [];
    legendBfb = [];
    for (let i = 0; i < series.length; i++) {
        endValue = startValue + series[i].pieData.value;
        series[i].pieData.startRatio = startValue / sumValue;
        series[i].pieData.endRatio = endValue / sumValue;
        series[i].parametricEquation = getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio,
            false, false, k, series[i].pieData.value);
        startValue = endValue;
        let bfb = fomatFloat(series[i].pieData.value / sumValue, 4);
        legendData.push({
            name: series[i].name,
            value: bfb
        });
        legendBfb.push({
            name: series[i].name,
            value: bfb
        });
        series[i].radius = [0, '75%']
    }
    //(第二个参数可以设置你这个环形的高低程度)
    let boxHeight = getHeight3D(series, 30);//通过传参设定3d饼/环的高度
    // 准备待返回的配置项，把准备好的 legendData、series 传入。
    let option = {
        //图例组件
        legend: {
            data: legendData,
            //图例列表的布局朝向。
            orient: 'vertical',
            right: 45,
            top: 10,
            //图例文字每项之间的间隔
            itemGap: 15,
            textStyle: {
                color: '#A1E2FF',
                fontSize:16,
            },
            show: true,
            icon: "circle",
            //格式化图例文本（我是数值什么显示什么）
            formatter: function (name) {
                var target;
                for (var i = 0, l = pieData.length; i < l; i++) {
                    if (pieData[i].name == name) {
                        target = pieData[i].value;
                    }
                }
                return `${name}   ${target}%`;
            }
            // 这个可以显示百分比那种（可以根据你想要的来配置）
            //   formatter: function(param) {
            //       let item = legendBfb.filter(item => item.name == param)[0];
            //       let bfs = fomatFloat(item.value * 100, 2) + "%";
            //       console.log(item.name)
            //       return `${item.name} :${bfs}`;
            //   }
        },
        //移动上去提示的文本内容(我没来得及改 你们可以根据需求改)
        tooltip: {
            formatter: params => {
                if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
                    let bfb = ((option.series[params.seriesIndex].pieData.endRatio - option.series[params.seriesIndex].pieData.startRatio) *
                        100).toFixed(2);
                    return `${params.seriesName}<br/>` +
                        `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
                        `${bfb}`;
                }
            }
        },
        //这个可以变形
        xAxis3D: {
            min: -1,
            max: 1
        },
        yAxis3D: {
            min: -1,
            max: 1
        },
        zAxis3D: {
            min: -1,
            max: 1
        },
        startAngle: 90,
        //此处是修改样式的重点
        grid3D: {
            show: false,
            boxHeight: boxHeight, //圆环的高度
            //这是饼图的位置
            top: '-18.5%',
            left: '-20%',
            viewControl: { //3d效果可以放大、旋转等，请自己去查看官方配置
                alpha: 35, //角度(这个很重要 调节角度的)
                distance: 200,//调整视角到主体的距离，类似调整zoom(这是整体大小)
                rotateSensitivity: 0, //设置为0无法旋转
                zoomSensitivity: 0, //设置为0无法缩放
                panSensitivity: 0, //设置为0无法平移
                autoRotate: false //自动旋转
            }
        },
        series: series
    };
    return option;

}
const getHeight3D = (series, height) => {
    series.sort((a, b) => {
        return (b.pieData.value - a.pieData.value);
    })
    return height * 25 / series[0].pieData.value;
}
const getParametricEquation = (startRatio, endRatio, isSelected, isHovered, k, h) => {
    // 计算
    let midRatio = (startRatio + endRatio) / 2;
    let startRadian = startRatio * Math.PI * 2;
    let endRadian = endRatio * Math.PI * 2;
    let midRadian = midRatio * Math.PI * 2;
    // 如果只有一个扇形，则不实现选中效果。
    if (startRatio === 0 && endRatio === 1) {
        isSelected = false;
    }
    // 通过扇形内径/外径的值，换算出辅助参数 k（默认值 1/3）
    k = typeof k !== 'undefined' ? k : 1 / 3;
    // 计算选中效果分别在 x 轴、y 轴方向上的位移（未选中，则位移均为 0）
    let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
    let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
    // 计算高亮效果的放大比例（未高亮，则比例为 1）
    let hoverRate = isHovered ? 1.05 : 1;
    // 返回曲面参数方程
    return {
        u: {
            min: -Math.PI,
            max: Math.PI * 3,
            step: Math.PI / 32
        },
        v: {
            min: 0,
            max: Math.PI * 2,
            step: Math.PI / 20
        },
        x: function (u, v) {
            if (u < startRadian) {
                return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
            }
            if (u > endRadian) {
                return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
            }
            return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
        },
        y: function (u, v) {
            if (u < startRadian) {
                return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
            }
            if (u > endRadian) {
                return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
            }
            return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
        },
        z: function (u, v) {
            if (u < -Math.PI * 0.5) {
                return Math.sin(u);
            }
            if (u > Math.PI * 2.5) {
                return Math.sin(u) * h * .1;
            }
            return Math.sin(v) > 0 ? 1 * h * .1 : -1;
        }
    };
}
const fomatFloat = (num, n) => {
    var f = parseFloat(num);
    if (isNaN(f)) {
        return false;
    }
    f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂   
    var s = f.toString();
    var rs = s.indexOf('.');
    //判定如果是整数，增加小数点再补0
    if (rs < 0) {
        rs = s.length;
        s += '.';
    }
    while (s.length <= rs + n) {
        s += '0';
    }
    return s;
}
const bindListen = (myChart) => {
    let selectedIndex = '';
    let hoveredIndex = '';
    // 监听点击事件，实现选中效果（单选）
    myChart.on('click', function (params) {
        // 从 option.series 中读取重新渲染扇形所需的参数，将是否选中取反。
        let isSelected = !option.series[params.seriesIndex].pieStatus.selected;
        let isHovered = option.series[params.seriesIndex].pieStatus.hovered;
        let k = option.series[params.seriesIndex].pieStatus.k;
        let startAngle = option.series[params.seriesIndex].startAngle;
        let endAngle = option.series[params.seriesIndex].endAngle;

        // 如果之前选中过其他扇形，将其取消选中（对 option 更新）
        if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
            option.series[selectedIndex].parametricEquation = getParametricEquation(option.series[
                selectedIndex].startAngle, option.series[selectedIndex].endAngle, false, false, k, option.series[
                    selectedIndex].data);
            option.series[selectedIndex].pieStatus.selected = false;
        }

        // 对当前点击的扇形，执行选中/取消选中操作（对 option 更新）
        option.series[params.seriesIndex].parametricEquation = getParametricEquation(startAngle, endAngle,
            isSelected, isHovered, k, option.series[params.seriesIndex].data);
        option.series[params.seriesIndex].pieStatus.selected = isSelected;

        // 如果本次是选中操作，记录上次选中的扇形对应的系列号 seriesIndex
        isSelected ? selectedIndex = params.seriesIndex : null;

        // 使用更新后的 option，渲染图表
        myChart.setOption(option);
    });
    // 监听 mouseover，近似实现高亮（放大）效果
    myChart.on('mousemove', function (params) {  
        // 监听 mousemove 事件
        let hoveredIndex = ''; // 记录上次高亮的扇形对应的系列号
        let option = myChart.getOption(); // 获取当前的 option

        // 遍历所有的 series，根据触发 mouseover 的扇形高亮，并取消其余扇形的高亮
        option.series.forEach(function (series, index) {
            let isSelected, isHovered, startAngle, endAngle;

            if (index === params.seriesIndex) { // 触发鼠标所在的扇形，设置其高亮状态
                if (hoveredIndex !== '' && hoveredIndex !== index) { // 如果存在上一次的高亮结果，取消它的高亮
                    resetSeries(option.series[hoveredIndex]);
                }
                isSelected = series.itemStyle.opacity === 0.6;  // 获取当前扇形的选中状态   
                isHovered = true;  // 设置高亮状态为 true
                startAngle = series.startAngle;  // 扇形起始角度，即开始渲染的弧度数值
                endAngle = series.endAngle;  // 扇形结束角度，即结束渲染的弧度数值

                option.series[index] = getUpdatedSeries(series, isSelected, isHovered, startAngle, endAngle);   // 更新当前扇形的 attr

                hoveredIndex = index;  // 记录当前高亮 This creates an effective hover effect on series in ECharts 3.0 by adding a translation effect that makes the clickable area of each item appear to be "lifted".
            } else if (series.itemStyle.opacity === 0.6) { // 如果该扇形正在选中，需要取消它的高亮效果
                resetSeries(series);
            }
        });
        myChart.setOption(option); // 将更新后的 option 渲染到图表上
        function resetSeries(series) {  // 取消该 series 的高亮效果
            let isSelected = series.itemStyle.opacity === 0.6;
            let isHovered = false;
            let startAngle = series.startAngle;
            let endAngle = series.endAngle;

            option.series[index] = getUpdatedSeries(series, isSelected, isHovered, startAngle, endAngle);
        }
        function getUpdatedSeries(series, isSelected, isHovered, startAngle, endAngle) { // 更新当前扇形的相关属性，并返回新的 series 对象
            let r = series.radius[1] + 5; // 半径增加 5px，用来实现高亮效果
            let parametricEquation = `return ${getParametricEquation(startAngle, endAngle, isSelected, isHovered, r)} * sin((theta*Math.PI/180));`; // 重新计算 parametricEquation

            return Object.assign({}, series, { // 返回一个新的对象，包含更新后的 attr 属性
                z2: isHovered ? 10 : 1,
                itemStyle: {
                    opacity: isSelected ? 0.6 : 1
                },
                labelLine: {
                    length: isHovered ? 12 : 6,
                    length2: 20,
                    smooth: true
                },
                parametricEquation: parametricEquation
            });
        }
        function getParametricEquation(startAngle, endAngle, isSelected, isHovered, r) { // 计算 parametricEquation
            let angleDiff = Math.abs(endAngle - startAngle) % 360 || 360;
            let k = Math.ceil(angleDiff / 30);
            return `(${isSelected ? '1.1' : (isHovered ? '1.05' : '1')} * ${r})/(1-${isSelected ? 't*0.1*' : ''}(Math.cos(${endAngle}*Math.PI/180*(t-${isSelected ? '0.3' : '0'
                })/${k})+Math.cos(${endAngle}*Math.PI/180*${isSelected ? '0.3' : '0'
                }/${k}))))`;
        }
        function getParametricEquation(startAngle , endAngle, isSelected, isHovered, r) { // 计算 parametricEquation
            let k = (endAngle - startAngle) / 360;
            let theta1 = `${startAngle.toFixed(0)}+((theta+${isSelected ? 3.5 : 0})*(theta<=8)?0:(theta>=352?7:theta*0.875))`;
            let theta2 = `${startAngle.toFixed(0)}+((theta+${isSelected ? 4 : 0})*(theta<=8)?0:(theta>=352?8:theta*0.875))`;

            return `return ${r}* sin(${theta1}*t+${k})*(1+${isHovered ? '0.03' : '0.005'}*t*(cos(${theta2}*(t-${isHovered ? 0.13 : 0})/${k})+cos(${theta2}*${isHovered ? '0.13' : '0'}/${k})));`;
        }
    });

    // 修正取消高亮失败的 bug
    myChart.on('mouseout', function () { // 监听 mouseout 事件
        let hoveredIndex = ''; // 清空当前高亮的扇形对应的系列号
        let option = myChart.getOption(); // 获取当前的 option

        // 遍历所有的 series，更新当前扇形的相关属性，并取消其高亮效果
        option.series.forEach(function (series, index) {
            if (series.pieStatus.hovered) { // 判断该扇形是否存在高亮状态
                let isSelected = series.pieStatus.selected;
                let isHovered = false;
                let k = series.pieStatus.k;
                let startRatio = series.pieData.startRatio;
                let endRatio = series.pieData.endRatio;

                series.parametricEquation = getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, series.pieData.value); // 更新 parametricEquation
                series.pieStatus.hovered = isHovered; // 取消该扇形的高亮状态
                hoveredIndex = ''; // 清空当前高亮的扇形对应的系列号
            }
        });

        myChart.setOption(option); // 将更新后的 option 渲染到图表上

        function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, value) { // 计算 parametricEquation
            return `return ${getStatusRadius(isSelected, isHovered, value)} * sin((${startRatio.toFixed(4)} + (theta*t/${k}))*Math.PI/180)*(1 - t*0.1*(Math.cos(${endRatio.toFixed(4)}*Math.PI/180*(t-0.3)/${k}) + Math.cos(${endRatio.toFixed(4)}*Math.PI/180*0.3/${k}))));`
        }

        function getStatusRadius(isSelected, isHovered, value) { // 计算扇形的半径
            return isSelected ? 1.1 * value : (isHovered ? 1.05 : 1) * value;
        }
    });



}
onMounted(() => {
    nextTick(function () {
        init();
    });
})
</script>
<template>
    <!-- 饼图 -->
    <div class="container">
        <div class="chartsGl" id="charts"></div>
        <!-- <div class="buttomCharts"></div> -->
    </div>
</template>
<style>
.container {
    width: 100%;
    height: 100%;
}

.chartsGl {
    height: 200px;
    width: 100%;
}

.buttomCharts {
    background: center top url(/src/assets/1@2x.png);
    background-size: cover;
    height: 78px;
    width: 180px;
    margin-top: -155px;
    margin-left: 18%;
}
</style>